package ${package.Controller};

<#if springdoc && Placeholder_ExistKnife4jExt>
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
</#if>
import ${package.Entity}.req.${originEntityName}AddReqVO;
<#if containExcelImportRe>
import ${package.Entity}.req.${originEntityName}ExcelImportReqVO;
</#if>
import ${package.Entity}.req.${originEntityName}ListReqVO;
import ${package.Entity}.req.${originEntityName}UpdateReqVO;
import ${package.Entity}.resp.${originEntityName}DetailRespVO;
import ${package.Entity}.resp.${originEntityName}ListRespVO;
import ${package.Service}.${table.serviceName};
import ${unified_pageInfo_class_long_name};
<#if containExcelImportRe>
import cn.hutool.core.io.resource.ResourceUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.enums.WriteDirectionEnum;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.ideaaedi.zoo.commonbase.entity.excel.ExcelImportDynamicHeaderDTO;
</#if>
<#if wrapControllerResult>
import ${unified_result_class_long_name};
</#if>
<#if superControllerClassPackage??>
import ${superControllerClassPackage};
</#if>
<#if springdoc>
    <#if Placeholder_ExistKnife4jExt>
import com.ideaaedi.zoo.diy.artifact.apidoc.knife4j.annotation.ApiTag;
    <#else>
import io.swagger.v3.oas.annotations.tags.Tag;
    </#if>
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
</#if>
import jakarta.annotation.Resource;
<#if containExcelImportRe>
import jakarta.servlet.http.HttpServletResponse;
</#if>
import jakarta.validation.constraints.NotNull;
<#if containExcelImportRe>
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FastByteArrayOutputStream;
</#if>
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
<#if containExcelImportRe>
import org.springframework.web.bind.annotation.RequestPart;
</#if>
<#if restControllerStyle>
import org.springframework.web.bind.annotation.RestController;
<#else>
import org.springframework.stereotype.Controller;
</#if>
<#if containExcelImportRe>
import org.springframework.web.multipart.MultipartFile;

import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
</#if>

/**
 * ${briefTableComment}
 *
 * @author ${author}
 * @since ${date}
 */
<#if containExcelImportRe>
@Slf4j
</#if>
@Validated
<#if restControllerStyle>
@RestController
<#else>
@Controller
</#if>
<#if springdoc>
<#if Placeholder_ExistKnife4jExt>
@ApiTag(name = "${briefTableComment}", order = 100)
<#else>
@Tag(name = "${briefTableComment}")
</#if>
</#if>
@RequestMapping("<#if package.ModuleName?? && package.ModuleName != "">/${package.ModuleName}</#if>/<#if controllerMappingHyphenStyle>${controllerMappingHyphen}<#else>${originEntityNameHyphenStyle}</#if>")
<#if kotlin>
class ${table.controllerName}<#if superControllerClass??> : ${superControllerClass}()</#if>
<#else>
<#if superControllerClass??>
public class ${table.controllerName} extends ${superControllerClass} {
<#else>
public class ${table.controllerName} {
</#if>

    @Resource
    private ${table.serviceName} ${customLowerServiceName};

    /**
     * 增
     *
     * @param req 参数
     *
     * @return 新增的数据详情
     */
    @PostMapping("/add")
    <#if springdoc>
    @Operation(summary = "增")
    <#if Placeholder_ExistKnife4jExt>
    @ApiOperationSupport(order = 10)
    </#if>
    </#if>
    public <#if wrapControllerResult>${unified_result_class_name}<</#if>${originEntityName}DetailRespVO<#if wrapControllerResult>></#if> add(@RequestBody @Validated ${originEntityName}AddReqVO req) {
        return <#if wrapControllerResult>${unified_result_class_name}.success(</#if>${customLowerServiceName}.add(req, true)<#if wrapControllerResult>)</#if>;
    }

    /**
     * 删
     *
     * @param id 要删除数据的id
     *
     * @return 删除了的数据详情
     */
    <#if springdoc>
    @Operation(summary = "删")
    </#if>
    @DeleteMapping("/delete/{id}")
    <#if springdoc && Placeholder_ExistKnife4jExt>
    @ApiOperationSupport(order = 20)
    </#if>
    public <#if wrapControllerResult>${unified_result_class_name}<</#if>${originEntityName}DetailRespVO<#if wrapControllerResult>></#if> delete(<#if springdoc>@Parameter(description = "要删除数据的id") </#if>@PathVariable("id")
                                                  @NotNull(message = "id cannot be null.") <#list customAllFields as field><#if field.keyFlag>${field.propertyType}</#if></#list> id) {
        return <#if wrapControllerResult>${unified_result_class_name}.success(</#if>${customLowerServiceName}.delete(id)<#if wrapControllerResult>)</#if>;
    }

    /**
     * 改
     *
     * @param req 参数
     *
     * @return 修改后的数据详情
     */
    @PutMapping("/update")
    <#if springdoc>
    @Operation(summary = "改")
    <#if Placeholder_ExistKnife4jExt>
    @ApiOperationSupport(order = 30)
    </#if>
    </#if>
    public <#if wrapControllerResult>${unified_result_class_name}<</#if>${originEntityName}DetailRespVO<#if wrapControllerResult>></#if> update(@RequestBody @Validated ${originEntityName}UpdateReqVO req) {
        return <#if wrapControllerResult>${unified_result_class_name}.success(</#if>${customLowerServiceName}.update(req)<#if wrapControllerResult>)</#if>;
    }

    /**
     * 查列表
     *
     * @param req 参数
     *
     * @return 数据列表
     */
    @PostMapping("/list")
    <#if springdoc>
    @Operation(summary = "查列表")
    </#if>
    <#if springdoc && Placeholder_ExistKnife4jExt>
    @ApiOperationSupport(order = 40)
    </#if>
    public <#if wrapControllerResult>${unified_result_class_name}<</#if>${unified_pageInfo_class_name}<${originEntityName}ListRespVO><#if wrapControllerResult>></#if> list(@RequestBody @Validated ${originEntityName}ListReqVO req) {
        return <#if wrapControllerResult>${unified_result_class_name}.success(</#if>${customLowerServiceName}.list(req)<#if wrapControllerResult>)</#if>;
    }

    /**
     * 查详情
     *
     * @param id 要查询数据的id
     *
     * @return 数据详情
     */
    <#if springdoc>
    @Operation(summary = "查详情")
    </#if>
    @GetMapping("/detail/{id}")
    <#if springdoc && Placeholder_ExistKnife4jExt>
    @ApiOperationSupport(order = 50)
    </#if>
    public <#if wrapControllerResult>${unified_result_class_name}<</#if>${originEntityName}DetailRespVO<#if wrapControllerResult>></#if> detail(<#if springdoc>@Parameter(description = "要查询数据的id") </#if>@PathVariable("id")
                                                  @NotNull(message = "id cannot be null.") <#list customAllFields as field><#if field.keyFlag>${field.propertyType}</#if></#list> id) {
        return <#if wrapControllerResult>${unified_result_class_name}.success(</#if>${customLowerServiceName}.detail(id)<#if wrapControllerResult>)</#if>;
    }
    <#if containExcelImportRe>

    /**
     * 获取excel导入模板
     *
     * @param httpServletResponse http响应
     */
    <#if springdoc>
    <#if Placeholder_ExistKnife4jExt>
    @ApiOperationSupport(order = 60)
    </#if>
    @Operation(summary = "获取excel导入模板")
    </#if>
    @PostMapping("/excel-import-template")
    public void excelImportTemplate(HttpServletResponse httpServletResponse) {
        Class<?> targetClazz = ${originEntityName}ExcelImportReqVO.class;
        String classDesc = "${briefTableComment}";
        /// step1. 获取要导出的excel列
        List<ExcelImportDynamicHeaderDTO> dynamicHeaderList = new ArrayList<>();
        for (Field declaredField : targetClazz.getDeclaredFields()) {
            ExcelProperty excelPropertyAnno = declaredField.getAnnotation(ExcelProperty.class);
            if (excelPropertyAnno == null) {
                continue;
            }
            String fieldDesc = excelPropertyAnno.value()[0];
            if (StringUtils.isBlank(fieldDesc)) {
                fieldDesc = declaredField.getName();
            }
            dynamicHeaderList.add(ExcelImportDynamicHeaderDTO.create(fieldDesc));
        }
        if (CollectionUtils.isEmpty(dynamicHeaderList)) {
            throw new IllegalStateException("there is no header information. target clazz is -> " + targetClazz.getName());
        }

        /// step2. 根据原始模板，动态生成当前业务对应的实时导入模板
        FastByteArrayOutputStream fastByteArrayOutputStream = new FastByteArrayOutputStream();
        ExcelWriterBuilder excelTemplateWriterBuilder = EasyExcel.write(fastByteArrayOutputStream)
                .withTemplate(ResourceUtil.getStream("${excelImportRawExcelTemplate}"));
        try (ExcelWriter excelWriter = excelTemplateWriterBuilder.build()) {
            excelWriter.fill(
                    new FillWrapper(dynamicHeaderList),
                    FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build(),
                    EasyExcel.writerSheet().build()
            );
            excelWriter.finish();
        }
        fastByteArrayOutputStream.close();
        byte[] excelBytes = fastByteArrayOutputStream.toByteArray();

        /// step3. 导入模板响应回客户端
        try {
            String excelFilename = URLEncoder.encode(classDesc + "导入模板", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
            httpServletResponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            httpServletResponse.setCharacterEncoding(StandardCharsets.UTF_8.name());
            // URLEncoder.encode防止中文乱码
            httpServletResponse.setHeader("Content-disposition", "attachment;filename*=utf-8''" + excelFilename + ".xlsx");
            httpServletResponse.getOutputStream().write(excelBytes);
            log.info("Change response json to do excel export(by stream) end.");
        } catch (Exception e) {
            log.error("download-excel-template occur exception.", e);
            if (!httpServletResponse.isCommitted()) {
                httpServletResponse.reset();
                httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
                httpServletResponse.setCharacterEncoding(StandardCharsets.UTF_8.name());
            }
            throw new RuntimeException(e);
        }
    }

    /**
     * excel导入
     *
     * @param file 文件
     *
     * @return 文件id
     */
    @SneakyThrows
    <#if springdoc>
    @Operation(summary = "excel导入")
    <#if Placeholder_ExistKnife4jExt>
    @ApiOperationSupport(order = 70)
    </#if>
    </#if>
    @PostMapping("/import-by-excel")
    public <#if wrapControllerResult>${unified_result_class_name}<</#if>Boolean<#if wrapControllerResult>></#if> excelImport(<#if springdoc>@Parameter(description = "excel文件")
                                           </#if>@RequestPart(value = "file") MultipartFile file) {
        // 读取excel
        List<${originEntityName}ExcelImportReqVO> excelDataList = EasyExcel.read(file.getInputStream())
                .head(${originEntityName}ExcelImportReqVO.class)
                .sheet()
                .doReadSync();
        if (CollectionUtils.isEmpty(excelDataList)) {
            log.info("excel-data-list is empty.");
            return <#if wrapControllerResult>${unified_result_class_name}.success(</#if>true<#if wrapControllerResult>)</#if>;
        }
        return <#if wrapControllerResult>${unified_result_class_name}.success(</#if>${customLowerServiceName}.excelImport(excelDataList)<#if wrapControllerResult>)</#if>;
    }
    </#if>

}</#if>